home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / pcmagwin.zip / SYSMON.C < prev    next >
Text File  |  1992-12-16  |  29KB  |  828 lines

  1. // SysMon - Simple System Monitor for Windows NT
  2. // Uses Performance Data Block in System Registry
  3. // Tested with Oct 92 (beta) Release of Windows NT
  4. // Copyright (C) 1992 Ray Duncan
  5. // PC Magazine * Ziff Davis Publishing
  6.  
  7. #define dim(x) (sizeof(x) / sizeof(x[0]))   // returns no. of elements
  8. #define MAXLINES 4096                       // max lines to display
  9. #define MALLOCINCR 4096
  10.  
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <windows.h>
  14. #include <winperf.h>
  15. #include "sysmon.h"
  16.  
  17. HANDLE hInst;                               // module instance handle
  18. HWND hFrame;                                // handle for frame window
  19. HFONT hFont;                                // handle for nonprop. font
  20.  
  21. int CharX, CharY;                           // character dimensions
  22. int LinesPerPage;                           // lines per page
  23. int CurLine = 0;                            // first line, current page
  24. int TotLines = 0;                           // total lines to display
  25. int TopLine = 0;                            // first line of last page
  26. int DisplayType = IDM_OBJECT;               // default display type
  27.  
  28. char *LinePtr[MAXLINES];                    // holds pointers to lines
  29.  
  30. char szFrameClass[] = "SysMon";             // classname for frame window
  31. char szAppName[] = "System Monitor";        // long application name
  32. char szMenuName[] = "SysMonMenu";           // name of menu resource
  33. char szIcon[] = "SysMonIcon";               // name of icon resource
  34. char szIni[] = "sysmon.ini";                // name of private INI file
  35.  
  36. DWORD dwPerfDataLen = 0;                    // size of performance data
  37. PPERFDATA pPerfData;                        // addr of perf data block
  38. PPERFGROUP pFirstGroup;                     // addr of first object group
  39. INT iTotGroups;                             // total object groups
  40. PSTR pTitles;                               // addr of object title database
  41.  
  42. //
  43. // Table of window messages supported by FrameWndProc()
  44. // and the functions which correspond to each message.
  45. //
  46. struct decodeMsg frameMsgs[] = {
  47.     WM_PAINT, DoPaint,
  48.     WM_SIZE, DoSize,
  49.     WM_COMMAND, DoCommand,
  50.     WM_SETFOCUS, DoSetFocus,
  51.     WM_CLOSE, DoClose,
  52.     WM_DESTROY, DoDestroy,
  53.     WM_VSCROLL, DoVScroll, } ;
  54.  
  55. //
  56. // Table of menubar item IDs and their corresponding functions.
  57. //
  58. struct decodeMsg menuitems[] = {
  59.     IDM_EXIT, DoMenuExit,
  60.     IDM_ABOUT, DoMenuAbout,
  61.     IDM_OBJECT, DoDisplayType,
  62.     IDM_PROCESS, DoDisplayType,
  63.     IDM_REFRESH, DoRefresh, } ;
  64.  
  65. //
  66. // WinMain -- entry point for this application from Windows.
  67. //
  68. int APIENTRY WinMain(HANDLE hInstance,
  69.     HANDLE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
  70. {
  71.     MSG msg;                                // scratch message storage
  72.     hInst = hInstance;                      // save this instance handle
  73.  
  74.     if(!InitApp(hInstance, nCmdShow))       // initialize everything
  75.     {
  76.         MessageBox(hFrame, "Initialization failed!", szAppName,
  77.             MB_ICONSTOP | MB_OK);
  78.         return(FALSE);
  79.     }
  80.  
  81.     while(GetMessage(&msg, NULL, 0, 0))     // while message != WM_QUIT
  82.     {
  83.         TranslateMessage(&msg);             // translate virtual key codes
  84.         DispatchMessage(&msg);              // dispatch message to window
  85.     }
  86.  
  87.     TermApp(hInstance);                     // clean up everything
  88.     return(msg.wParam);                     // return code = WM_QUIT value
  89. }
  90.  
  91. //
  92. // InitApp --- application initialization code.
  93. //
  94. BOOL InitApp(HANDLE hInstance, int nCmdShow)
  95. {
  96.     WNDCLASS  wc;                           // window class info
  97.     HDC hdc;                                // handle for device context
  98.     TEXTMETRIC tm;                          // info about font
  99.     RECT rect;                              // window position & size
  100.     int i;                                  // scratch variable
  101.  
  102.     // set parameters for frame window class
  103.     wc.style = CS_HREDRAW|CS_VREDRAW;       // class style
  104.     wc.lpfnWndProc = FrameWndProc;          // class callback function
  105.     wc.cbClsExtra = 0;                      // extra per-class data
  106.     wc.cbWndExtra = 0;                      // extra per-window data
  107.     wc.hInstance = hInstance;               // handle of class owner
  108.     wc.hIcon = LoadIcon(hInst, szIcon);     // application icon
  109.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);       // default cursor
  110.     wc.hbrBackground = GetStockObject(WHITE_BRUSH); // background color 
  111.     wc.lpszMenuName =  szMenuName;          // name of menu resource
  112.     wc.lpszClassName = szFrameClass;        // name of window class
  113.  
  114.     // register frame window class, abort application if fails
  115.     if(!RegisterClass(&wc))
  116.         return(FALSE);
  117.  
  118.     for(i = 0; i < MAXLINES; i++)           // initialize all line
  119.         LinePtr[i] = NULL;                  // pointers
  120.  
  121.     hFrame = CreateWindow(                  // create frame window
  122.         szFrameClass,                       // window class name
  123.         szAppName,                          // text for title bar
  124.         WS_OVERLAPPEDWINDOW | WS_VSCROLL,   // window style
  125.         CW_USEDEFAULT, CW_USEDEFAULT,       // default position
  126.         CW_USEDEFAULT, CW_USEDEFAULT,       // default size
  127.         NULL,                               // no parent window
  128.         NULL,                               // use class default menu
  129.         hInstance,                          // window owner
  130.         NULL);                              // unused pointer
  131.  
  132.     if(!hFrame) return(FALSE);              // error, can't create window
  133.  
  134.     hdc = GetDC(hFrame);                    // get device context
  135.     hFont = GetStockObject(SYSTEM_FIXED_FONT);  // handle for nonprop. font
  136.     SelectObject(hdc, hFont);               // realize the font and get
  137.     GetTextMetrics(hdc, &tm);               // the character dimensions
  138.     CharX = tm.tmAveCharWidth;
  139.     CharY = tm.tmHeight + tm.tmExternalLeading;
  140.     ReleaseDC(hFrame, hdc);                 // release device context
  141.  
  142.     GetWindowRect(hFrame, &rect);           // current window pos & size
  143.  
  144.     // read profile for frame window from previous invocation, if any
  145.     rect.left   = GetPrivateProfileInt("Frame", "xul", rect.left, szIni);
  146.     rect.top    = GetPrivateProfileInt("Frame", "yul", rect.top, szIni);
  147.     rect.right  = GetPrivateProfileInt("Frame", "xlr", rect.right, szIni);
  148.     rect.bottom = GetPrivateProfileInt("Frame", "ylr", rect.bottom, szIni);
  149.  
  150.     MoveWindow(hFrame, rect.left, rect.top, // force window size & position
  151.         rect.right-rect.left, rect.bottom-rect.top, TRUE);
  152.  
  153.     // get display type from previous invocation, default to module list
  154.     DisplayType = GetPrivateProfileInt("Frame", "type", IDM_OBJECT, szIni);
  155.  
  156.     // allocate initial buffer to receive performance data
  157.     // this buffer will be grown as necessary by GetPerfData
  158.     dwPerfDataLen = MALLOCINCR;
  159.     pPerfData = (PPERFDATA) malloc(dwPerfDataLen);
  160.     if(pPerfData == NULL)
  161.         return(FALSE);
  162.  
  163.     // fetch names of object types from system registry
  164.     if(!GetObjectTitles())
  165.         return(FALSE);
  166.  
  167.     // fetch system performance data from system registry
  168.     if(!GetPerfData())
  169.         return(FALSE);
  170.  
  171.     // set up our 10 sec. (10,000 msec) timer callback
  172.     if (!SetTimer(hFrame, 1, 10000, (WNDPROC) TimerProc))
  173.         return(FALSE);
  174.  
  175.     ShowWindow(hFrame, nCmdShow);           // make frame window visible
  176.  
  177.     // simulate a Display menu command to turn on the menu checkmark
  178.     // for the current display type, and force update of the window
  179.     PostMessage(hFrame, WM_COMMAND, DisplayType, 0);
  180.  
  181.     return(TRUE);                           // return success flag
  182. }
  183.  
  184. //
  185. // TermApp -- centralized clean-up code for application.
  186. //            Does nothing in this particular implementation.
  187. //
  188. BOOL TermApp(HANDLE hinstance)
  189. {
  190.     return(TRUE);                           // return success flag
  191. }
  192.  
  193. //
  194. // FrameWndProc --- callback function for application frame window.
  195. // Searches frameMsgs[] for message match, runs corresponding function.
  196. //
  197. LONG CALLBACK FrameWndProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  198. {
  199.     int i;                                  // scratch variable
  200.  
  201.     for(i = 0; i < dim(frameMsgs); i++)     // decode window message and
  202.     {                                       // run corresponding function
  203.         if(wMsg == frameMsgs[i].Code)
  204.             return((*frameMsgs[i].Fxn)(hWnd, wMsg, wParam, lParam));
  205.     }
  206.  
  207.     return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  208. }
  209.  
  210. //
  211. // DoCommand -- process WM_COMMAND message for frame window by
  212. // decoding the menubar item with the menuitems[] array, then
  213. // running the corresponding function to process the command.
  214. // 
  215. LONG DoCommand(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  216. {
  217.     int i;                                  // scratch variable
  218.  
  219.     for(i = 0; i < dim(menuitems); i++)     // decode menu command and
  220.     {                                       // run corresponding function
  221.         if(wParam == menuitems[i].Code)
  222.             return((*menuitems[i].Fxn)(hWnd, wMsg, wParam, lParam));
  223.     }
  224.  
  225.     return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  226. }
  227.  
  228. //
  229. // DoDestroy -- process WM_DESTROY message for frame window.
  230. // 
  231. LONG DoDestroy(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  232. {
  233.     PostQuitMessage(0);                     // force WM_QUIT message to
  234.     return(0);                              // terminate the event loop
  235. }
  236.  
  237. //
  238. // DoClose -- process WM_CLOSE message for frame window.
  239. // 
  240. LONG DoClose(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  241. {
  242.     UpdateProfile();                        // save window size & position
  243.     DestroyWindow(hWnd);                    // then close down app
  244.     return(FALSE);                              
  245. }
  246.  
  247. //
  248. // DoVScroll -- process WM_VSCROLL message for frame window.
  249. // 
  250. LONG DoVScroll(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  251. {
  252.     RECT rect;
  253.  
  254.     switch(LOWORD(wParam))                  // LOWORD vital for Win32
  255.     {                                   
  256.         case SB_TOP:                        // go to top of output if
  257.             if(CurLine)                     // we aren't there already
  258.             {
  259.                 SetCurLine(0);
  260.                 Repaint();
  261.             }
  262.             break;
  263.  
  264.         case SB_BOTTOM:                     // go to bottom of output if
  265.             if(CurLine < TopLine)           // we aren't there already
  266.             {
  267.                 SetCurLine(TopLine);
  268.                 Repaint();
  269.             }
  270.             break;
  271.  
  272.         case SB_LINEUP:                     // scroll up by one line if
  273.             if(CurLine)                     // we aren't already at top
  274.             {   
  275.                 SetCurLine(CurLine - 1);
  276.                 ScrollWindow(hWnd, 0, CharY, NULL, NULL);
  277.                 UpdateWindow(hWnd);
  278.             }
  279.             break;
  280.  
  281.         case SB_LINEDOWN:                   // scroll down by one line if
  282.             if(CurLine < TopLine)           // we aren't already at bottom
  283.             {
  284.                 SetCurLine(CurLine + 1);
  285.                 ScrollWindow(hWnd, 0, -CharY, NULL, NULL);
  286.                 GetClientRect(hWnd, &rect);
  287.                 rect.top = max(0, (LinesPerPage-1) * CharY);
  288.                 InvalidateRect(hWnd, &rect, TRUE);
  289.                 UpdateWindow(hWnd);
  290.             }
  291.             break;
  292.  
  293.         case SB_PAGEUP:                     // scroll up by one page
  294.             SetCurLine(CurLine - LinesPerPage);
  295.             Repaint();
  296.             break;
  297.  
  298.         case SB_PAGEDOWN:                   // scroll down by one page
  299.             SetCurLine(CurLine + LinesPerPage);
  300.             Repaint();
  301.             break;
  302.  
  303.         case SB_THUMBPOSITION:              // scroll display according
  304.             SetCurLine(THUMBPOS);           // to new thumb position
  305.             Repaint();
  306.             break;
  307.     }
  308.     return(FALSE);                              
  309. }
  310.  
  311. //
  312. // DoPaint -- process WM_PAINT message for frame window.
  313. // 
  314. LONG DoPaint(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  315. {
  316.     HDC hdc;
  317.     PAINTSTRUCT ps;
  318.     int i;
  319.  
  320.     hdc = BeginPaint(hWnd, &ps);            // get device context
  321.     SelectObject(hdc, hFont);               // select non-prop. font
  322.  
  323.     for(i = 0; i < LinesPerPage; i++)       // paint lines of text
  324.         PaintLine(hdc, i);                  // in the window
  325.  
  326.     EndPaint(hWnd, &ps);                    // release device context
  327.     return(FALSE);
  328. }
  329.  
  330. //
  331. // DoSize -- process WM_SIZE message for frame window.  Recalculate
  332. // lines per page, if window has grown and at end of file may need to 
  333. // change first line in window and refresh it.
  334. //
  335. LONG DoSize(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  336. {
  337.     LinesPerPage = HIWORD(lParam) / CharY;  // window height / char height
  338.     ConfigWindow();                         // calc display parameters
  339.     if(CurLine > TopLine)                   // make sure window refilled
  340.         SetCurLine(TopLine);                // if window got bigger
  341.     return(FALSE);
  342. }
  343.  
  344. //
  345. // DoSetFocus -- process WM_SETFOCUS message for frame window.
  346. // Refresh display in case something has changed since last in foreground.
  347. // This also gets called when app is launched after window is created.
  348. //
  349. LONG DoSetFocus(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  350. {
  351.     SendMessage(hFrame, WM_COMMAND, IDM_REFRESH, 0); 
  352.     return(FALSE);
  353. }
  354.  
  355. //
  356. // DoMenuExit -- process File-Exit command from menu bar.
  357. // 
  358. LONG DoMenuExit(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  359. {
  360.     SendMessage (hWnd, WM_CLOSE, 0, 0L);    // send window close message    
  361.     return(FALSE);                          // to shut down the app
  362. }
  363.  
  364. //
  365. // DoDisplayType -- process items on Display popup to select
  366. // the type of information to display, then force window update
  367. // 
  368. LONG DoDisplayType(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  369. {
  370.     HMENU hMenu;                            // scratch menu handle
  371.  
  372.     hMenu = GetMenu(hWnd);                  // update popup checkmark
  373.     CheckMenuItem(hMenu, DisplayType, MF_UNCHECKED);
  374.     DisplayType = wParam;                   
  375.     CheckMenuItem(hMenu, DisplayType, MF_CHECKED);
  376.     SendMessage(hWnd, WM_COMMAND, IDM_REFRESH, 0);  // update window
  377.     return(FALSE);
  378. }
  379.  
  380. //
  381. // DoRefresh -- rebuild the information for display according to
  382. // the currently selected display type, then refresh the window.
  383. // 
  384. LONG DoRefresh(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  385. {
  386.     EmptyLines();                           // discard old output
  387.  
  388.     // fetch fresh copy of system performance data block
  389.     GetPerfData();
  390.  
  391.     // call the appropriate list walking routine
  392.     // according to the currently selected display type
  393.     switch(DisplayType)                     
  394.     {                                       
  395.         case IDM_OBJECT:
  396.             WalkObjects();
  397.             SetWindowCaption("Objects");
  398.             break;
  399.  
  400.         case IDM_PROCESS:
  401.             WalkProcesses();
  402.             SetWindowCaption("Processes");
  403.             break;
  404.     }
  405.  
  406.     ConfigWindow();                         // configure scroll bar etc.
  407.     Repaint();                              // refresh the window
  408.  
  409.     return(FALSE);
  410. }
  411.  
  412. //
  413. // DoMenuAbout -- process File-About command from menu bar.
  414. // 
  415. LONG DoMenuAbout(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
  416. {
  417.     // allocate a thunk for the dialog callback, then display dialog
  418.     DialogBox(hInst, "AboutBox", hWnd, (WNDPROC) AboutDlgProc);         
  419.     return(FALSE);                              
  420. }
  421.  
  422. //
  423. // AboutDlgProc -- callback routine for About... dialog.  Basically
  424. // ignores all messages except for the OK button, which dismisses dialog.
  425. //
  426. BOOL CALLBACK AboutDlgProc (HWND hwnd, UINT msg, UINT wParam, LONG lParam)
  427. {
  428.     if((msg == WM_COMMAND) && (wParam == IDOK)) 
  429.         EndDialog(hwnd, 0);                 // if OK button, destroy dialog
  430.     else return(FALSE);                     // otherwise ignore message
  431. }
  432.  
  433. // 
  434. // WalkObjects -- Lists the object types found in the system
  435. // registry and the number of counters and instances for each.
  436. //
  437. VOID WalkObjects(VOID)
  438. {
  439.     char temp[256];
  440.     INT iCurGroup;
  441.     PPERFGROUP pCurGroup;
  442.  
  443.     // format title for itemized data
  444.     AddLine("Group  Description                      Counters  Instances"); 
  445.  
  446.     // begin at first object group
  447.     pCurGroup = pFirstGroup;
  448.  
  449.     // walk through object groups, printing for each the position,
  450.     // object type name, number of counters, and number of instances
  451.  
  452.     for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
  453.     {
  454.         wsprintf(temp, "%3d    %-32s %5d     %5d", iCurGroup, 
  455.                 pCurGroup->ObjectNameTitle,
  456.                 pCurGroup->NumCounters, pCurGroup->NumInstances);
  457.         AddLine(temp);
  458.  
  459.         // advance to next group of objects
  460.         pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup + 
  461.                     pCurGroup->TotalByteLength);
  462.     }
  463. }
  464.  
  465. // 
  466. // WalkProcesses -- displays process instances and counters from the 
  467. // system performance registry.
  468. //
  469. VOID WalkProcesses(VOID)
  470. {
  471.     char temp[256];
  472.     PPERFGROUP pCurGroup;
  473.     PPERFINSTANCE pCurInst;
  474.     PPERFCOUNTERS pCurCounters;
  475.     INT iCurInst;
  476.     INT iTotInst;
  477.  
  478.     // find appropriate object group within the performance data
  479.     pCurGroup = FindGroup("Process");
  480.  
  481.     // bail out now if there is nothing to display
  482.     if(pCurGroup == NULL)
  483.     {
  484.         AddLine("Process object group was not found!");
  485.         return;
  486.     }
  487.  
  488.     // extract pointer to first instance and total number of
  489.     // instances from the header for the process object group
  490.     pCurInst = (PPERFINSTANCE) ((PBYTE) pCurGroup + 
  491.                     pCurGroup->DefinitionLength);
  492.     iTotInst = pCurGroup->NumInstances;
  493.  
  494.     for(iCurInst = 0; iCurInst < iTotInst; iCurInst++)
  495.     {
  496.  
  497.         // convert UNICODE process name to ASCIIZ and display it
  498.         wcstombs(temp, (LPWSTR) ((PBYTE) pCurInst + pCurInst->NameOffset),
  499.                  pCurInst->NameLength/sizeof (WCHAR));
  500.         AddLine(temp);
  501.  
  502.         // advance to next process instance 
  503.         pCurCounters = (PPERFCOUNTERS) ((PBYTE) pCurInst +
  504.                        pCurInst->ByteLength);
  505.         pCurInst = (PPERFINSTANCE) ((PBYTE) pCurCounters +
  506.                    pCurCounters->ByteLength);
  507.     }
  508. }
  509.  
  510. //
  511. // SetCurLine - called to set CurLine to valid value, clamped to
  512. // the range (0...TopLine), and redraw thumb on scroll bar.
  513. //
  514. VOID SetCurLine(int NewLine)
  515. {
  516.     CurLine = min(max(NewLine, 0), TopLine);
  517.     SetScrollPos(hFrame, SB_VERT, CurLine, TRUE);
  518. }
  519.  
  520. //
  521. // ConfigWindow -- Configures various display parameters and scrollbar
  522. // according to total lines of output, current window size, and the
  523. // number of lines that will fit into the window.
  524. //
  525. VOID ConfigWindow(VOID)
  526. {
  527.     // calc line number of first line of last page
  528.     TopLine = max(TotLines - LinesPerPage,0);
  529.     
  530.     // update scroll bar range and thumb position
  531.     SetScrollRange(hFrame, SB_VERT, 0, TopLine, FALSE);
  532.     SetScrollPos(hFrame, SB_VERT, CurLine, TRUE);
  533. }
  534.  
  535. //
  536. // AddLine -- called with a pointer to an ASCIIZ string, allocates
  537. // memory from the heap to hold the string, puts the pointer
  538. // to the heap block into the next position in the LinePtr[] array,
  539. // and updates the total line count.
  540. //
  541. VOID AddLine(char * p)
  542. {
  543.     char * q;                               // scratch pointer
  544.  
  545.     if(TotLines == MAXLINES)                // bail out if line pointer
  546.         return;                             // array is already full
  547.     q = malloc(strlen(p)+1);                // allocate memory for line
  548.     if(q == 0)                              // bail out out if no 
  549.         return;                             // heap space available
  550.     strcpy(q, p);                           // copy string to heap
  551.     LinePtr[TotLines] = q;                  // put heap pointer into array
  552.     TotLines++;                             // count lines of output
  553. }
  554.  
  555. //
  556. // EmptyLines - releases all heap blocks in LinePtr[] array,
  557. // then zeros out the line pointers and the total line count
  558. //
  559. VOID EmptyLines(VOID)
  560. {
  561.     int i;                                  // scratch variable
  562.  
  563.     for(i = 0; i < MAXLINES; i++)
  564.     {
  565.         if(LinePtr[i])                      // if this position in
  566.         {                                   // the LinePtr array is
  567.             free(LinePtr[i]);               // nonzero, release the
  568.             LinePtr[i] = NULL;              // heap block, then zero
  569.         }                                   // out the LinePtr slot
  570.     }
  571.  
  572.     CurLine = 0;                            // initialize various
  573.     TotLines = 0;                           // other global variables
  574.     TopLine = 0;
  575. }
  576.  
  577. //
  578. // PaintLine -- paint a single line of text in the window.
  579. // The passed line number is relative to the window, NOT to the
  580. // total array of formatted output available to be painted.
  581. //
  582. VOID PaintLine(HDC hdc, INT RelLine)
  583. {
  584.     int Line = RelLine + CurLine;
  585.     if(LinePtr[Line])
  586.         TextOut(hdc, CharX, RelLine*CharY, LinePtr[Line], strlen(LinePtr[Line]));
  587. }
  588.  
  589. //
  590. // Repaint - force repaint of all formatted output in main window
  591. //
  592. VOID Repaint(VOID)
  593. {
  594.     InvalidateRect(hFrame, NULL, TRUE);     // force repaint entire window
  595. }
  596.  
  597. //
  598. // SetWindowCaption -- concatenate the application name with the
  599. // display type, then update the frame window's title bar.
  600. //
  601. VOID SetWindowCaption(char * szDisplayType)
  602. {
  603.     char szTemp[256];                       // scratch buffer
  604.  
  605.     strcpy(szTemp, szAppName);              // get application name
  606.     strcat(szTemp, " - ");                  // add separator
  607.     strcat(szTemp, szDisplayType);          // add information type
  608.     SetWindowText(hFrame, szTemp);          // put result into title bar
  609. }
  610.  
  611. //
  612. // UpdateProfile() --  saves the current window size and position
  613. // and display type in the application's private INI file.
  614. //
  615. VOID UpdateProfile(VOID)
  616. {
  617.     RECT rect;
  618.     char temp[20];
  619.  
  620.     if(IsIconic(hFrame) || IsZoomed(hFrame)) return;
  621.  
  622.     GetWindowRect(hFrame, &rect);           
  623.  
  624.     wsprintf(temp,"%d", rect.left);
  625.     WritePrivateProfileString("Frame", "xul", temp, szIni);
  626.  
  627.     wsprintf(temp,"%d", rect.top);
  628.     WritePrivateProfileString("Frame", "yul", temp, szIni);
  629.  
  630.     wsprintf(temp,"%d", rect.right);
  631.     WritePrivateProfileString("Frame", "xlr", temp, szIni);
  632.  
  633.     wsprintf(temp,"%d", rect.bottom);
  634.     WritePrivateProfileString("Frame", "ylr", temp, szIni);
  635.  
  636.     wsprintf(temp,"%d", DisplayType);
  637.     WritePrivateProfileString("Frame", "type", temp, szIni);
  638. }
  639.  
  640. //
  641. // TimerProc() -- Callback for 10 second timer. Refresh display
  642. // if window is not minimized and does not have the focus.
  643. // 
  644. WORD CALLBACK TimerProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
  645. {
  646.     if((!IsIconic(hFrame)) && (hFrame != GetFocus()))
  647.         SendMessage(hFrame, WM_COMMAND, IDM_REFRESH, 0); 
  648.     return(FALSE);                          
  649. }
  650.  
  651. //
  652. // GetPerfData() - obtain performance data block from the 
  653. // system registry.  The size of the data cannot be known in advance
  654. // so the buffer is expanded incrementally until it is big enough.
  655. //
  656. BOOL GetPerfData(VOID)
  657. {  
  658.     INT iCurGroup;
  659.     PPERFGROUP pCurGroup;
  660.     DWORD dwBufferSize = dwPerfDataLen;
  661.  
  662.     while(ERROR_MORE_DATA == 
  663.           RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", 
  664.             NULL, NULL, (PSTR) pPerfData, &dwBufferSize))
  665.     {
  666.  
  667.         dwPerfDataLen += MALLOCINCR;
  668.         dwBufferSize = dwPerfDataLen;
  669.         pPerfData = (PPERFDATA) realloc(pPerfData, dwPerfDataLen);
  670.  
  671.         if(pPerfData == NULL)
  672.         {
  673.             MessageBox(hFrame, "GetPerfData malloc failed!", szAppName,
  674.                 MB_ICONSTOP | MB_OK);
  675.             return(FALSE);
  676.         }
  677.     }
  678.  
  679.     // point to first object group within the data block and
  680.     // save total number of object groups
  681.     pFirstGroup = (PPERFGROUP) ((PBYTE) pPerfData + pPerfData->HeaderLength);
  682.     iTotGroups = pPerfData->NumObjectTypes;
  683.  
  684.     // point to the first group of objects
  685.     pCurGroup = pFirstGroup;
  686.  
  687.     // look up titles for each object type and save pointer
  688.     // within the object group's header structure
  689.     for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
  690.     {
  691.         pCurGroup->ObjectNameTitle = (LPWSTR)
  692.             FindTitle(pCurGroup->ObjectNameTitleIndex);
  693.  
  694.         // advance to next group of objects
  695.         pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup + 
  696.                     pCurGroup->TotalByteLength);
  697.     }
  698.  
  699.     return(TRUE);
  700. }  
  701.  
  702. //
  703. // GetObjectTitles() - retrieve titles for each of the object
  704. // types from the system registry.  The retrieved data, which is
  705. // referred to as the title database, is in the form of a series of
  706. // pairs of ASCIIZ strings.  The first string of a pair is the object
  707. // type index in decimal, the second string is the title.  The entire 
  708. // set of strings is terminated by an extra null byte.
  709. //
  710. BOOL GetObjectTitles(VOID)
  711. {
  712.     HKEY hKey;
  713.     char  chClass[10];
  714.     DWORD dwType;
  715.     DWORD cSubKeys;    
  716.     DWORD cbMaxSubkey; 
  717.     DWORD cbMaxClass;  
  718.     DWORD cValues; 
  719.     DWORD cbMaxValueName;
  720.     DWORD cbMaxValueData;  
  721.     DWORD cbSecurityDescriptor;    
  722.     DWORD cbClassSize = 10 ; // sizeof(chClass);
  723.     FILETIME ftLastWriteTime;
  724.  
  725.     // get handle for subkey holding object type indexes and titles
  726.     if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  727.         "Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\409", 
  728.         0, KEY_QUERY_VALUE, &hKey))
  729.     {
  730.         MessageBox(hFrame, "RegOpenKeyEx failed!", szAppName,
  731.             MB_ICONSTOP | MB_OK);
  732.         return(FALSE);
  733.     }
  734.  
  735.     // get maximum size of value data for values reached thru this subkey
  736.     if(ERROR_SUCCESS != RegQueryInfoKey(hKey, chClass, &cbClassSize, NULL, 
  737.         &cSubKeys, &cbMaxSubkey, &cbMaxClass, &cValues, &cbMaxValueName, 
  738.         &cbMaxValueData, &cbSecurityDescriptor, &ftLastWriteTime))
  739.     {
  740.         MessageBox(hFrame, "RegQueryInfoKey failed!", szAppName,
  741.             MB_ICONSTOP | MB_OK);
  742.         RegCloseKey(hKey);
  743.         return(FALSE);
  744.     }
  745.  
  746.     // bump maximum data size value for safety
  747.     cbMaxValueData++;
  748.  
  749.     // allocate memory to hold the incoming data
  750.     pTitles = malloc(cbMaxValueData * sizeof(TCHAR));
  751.  
  752.     if(pTitles == NULL)
  753.     {
  754.         MessageBox(hFrame, "GetObjectTitles malloc failed!", szAppName,
  755.             MB_ICONSTOP | MB_OK);
  756.         RegCloseKey(hKey);
  757.         return(FALSE);
  758.     }
  759.  
  760.     // now retrieve the index and title data
  761.     if(ERROR_SUCCESS != RegQueryValueEx(hKey, "Counters", NULL, &dwType,
  762.         (LPBYTE) pTitles, &cbMaxValueData))
  763.     {
  764.         MessageBox(hFrame, "RegQueryValueEx failed!", szAppName,
  765.             MB_ICONSTOP | MB_OK);
  766.         RegCloseKey(hKey);
  767.         return(FALSE);
  768.     }
  769.  
  770.     // release the handle for the subkey
  771.     RegCloseKey(hKey);
  772.     return(TRUE);
  773. }
  774.  
  775. // 
  776. // FindTitle() -- look up the object type index in the title database 
  777. // that was read by GetObjectTitles().  Return a pointer to the title
  778. // string if a match is found, otherwise return a pointer to "Unknown".
  779. // 
  780. PSTR FindTitle(INT TitleIndex)
  781. {
  782.     INT i;                                  // scratch object index
  783.     PSTR p = pTitles;                       // start of title database
  784.  
  785.     while(*p)                               
  786.     {
  787.         i = atoi(p);                        // convert index string
  788.         p += strlen(p) + 1;                 // point to title string
  789.         
  790.         if(i == TitleIndex)                 // is this desired index?
  791.             return(p);                      // yes, return addr of title
  792.  
  793.         p += strlen(p) + 1;                 // no, go to next index
  794.     }
  795.  
  796.     return("Unknown");                      // no match was found
  797. }
  798.  
  799. // 
  800. // FindGroup() -- Searches for the object group which has the
  801. // specified title.  Returns pointer to the beginning of the group's
  802. // instance storage if match is found, otherwise a NULL pointer.
  803. //
  804. PPERFGROUP FindGroup(PSTR GroupName)
  805. {
  806.     INT iCurGroup;
  807.     PPERFGROUP pCurGroup;
  808.  
  809.     // point to the first group of objects
  810.     pCurGroup = pFirstGroup;
  811.  
  812.     // compare title for each object type against supplied string
  813.     for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
  814.     {
  815.         // if titles match, return pointer to first instance
  816.         if(!strcmp((PSTR) pCurGroup->ObjectNameTitle, GroupName))
  817.             return(pCurGroup);
  818.  
  819.         // advance to next group of objects
  820.         pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup + 
  821.                     pCurGroup->TotalByteLength);
  822.     }
  823.  
  824.     return(NULL);                           // no match was found
  825. }
  826.  
  827.  
  828.